package com.wontube.media;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * @author yuechao
 *
 */
public final class AACWriter implements IAudioWriter {
	private File file;
	private RandomAccessFile fs;
	private int aacProfile;
	private int sampleRateIndex;
	private int channelConfig;
	
	public AACWriter(String path) throws IOException {
		this.file = new File(path);
		this.fs = new RandomAccessFile(this.file, "rw");
	}
	
	/* 
	 * @see com.wontube.media.IAudioWriter#writeChunk(byte[], long)
	 */
	@Override
	public void writeChunk(byte[] chunk, long timeStamp) throws IOException {
		if (chunk.length < 1) {
			return;
		}

		if (chunk[0] == 0) { // Header
			if (chunk.length < 3) {
				return;
			}

			long bit = (long)BitConverterBE.toUInt16(chunk, 1) << 48;
			long[] bits = new long[] { bit };

			this.aacProfile = BitHelper.read(bits, 5) - 1;
			this.sampleRateIndex = BitHelper.read(bits, 4);
			this.channelConfig = BitHelper.read(bits, 4);

			if ((this.aacProfile < 0) || (this.aacProfile > 3)) {
				throw new IOException("Unsupported AAC profile.");
			}
			if (this.sampleRateIndex > 12) {
				throw new IOException("Invalid AAC sample rate index.");
			}
			if (this.channelConfig > 6) {
				throw new IOException("Invalid AAC channel configuration.");
			}
		} else { // Audio data
			int dataSize = chunk.length - 1;
			long bit = 0;
			long[] bits = new long[] { bit };

			// Reference: WriteADTSHeader from FAAC's bitstream.c
			BitHelper.write(bits, 12, 0xFFF);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 2, 0);
			BitHelper.write(bits, 1, 1);
			BitHelper.write(bits, 2, this.aacProfile);
			BitHelper.write(bits, 4, this.sampleRateIndex);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 3, this.channelConfig);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 1, 0);
			BitHelper.write(bits, 13, 7 + dataSize);
			BitHelper.write(bits, 11, 0x7FF);
			BitHelper.write(bits, 2, 0);

			this.fs.write(BitConverterBE.getLongBytes(bits[0]), 1, 7);
			this.fs.write(chunk, 1, dataSize);
		}
	}

	/*
	 * @see com.wontube.media.IAudioWriter#finish()
	 */
	@Override
	public void finish() throws IOException {
		this.fs.close();
	}

	/* 
	 * @see com.wontube.media.IAudioWriter#getFile()
	 */
	@Override
	public File getFile() {
		return this.file;
	}
}
